using System;
using System.Collections.Generic;
using System.Text;
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Analysis;
using Lucene.Net.Documents;
using Lucene.Net.QueryParsers;

namespace Bots.Search
{
    public class ParseException:ApplicationException{
        public ParseException(string message) : base(message) { }
    }

    /// <summary>
    /// Lucene includes an interesting feature that parses query expressions throught the QueryParser class.
    /// It prases rich expressions such as (java and .net) into one of the Query implementations.
    /// Dealing with human-entered queries is the primary purpose of the QueryParser
    /// QueryParser translates query expression into one of lucene's built-in query types.
    /// Expression examples that QueryParser handles
    /// ---------------------------------------------------------------------------------
    /// java unit                   | contain the term java or unit in the default field
    /// java or unit                |
    /// ---------------------------------------------------------------------------------
    /// +java +unit                 | contain both java and unit in the default field.
    /// java and unit               |
    /// ---------------------------------------------------------------------------------
    /// title:ant                   | contain the term ant in the title field
    /// ---------------------------------------------------------------------------------
    /// title:extreme               | contain the term extreme in the title field and
    /// -subject:sports             | don't have the sports in the subject field
    /// title:extreme               |
    /// AND NOT subject:sports      |
    /// ---------------------------------------------------------------------------------
    /// title:"lucene in action"    | contain the exact phrase "lucene in action" in the title field
    /// ---------------------------------------------------------------------------------
    /// java*                       | contain terms that begin with java, like javascript                         
    /// ---------------------------------------------------------------------------------
    /// java~                       | contain terms that are close to the word java, such as lava
    /// ---------------------------------------------------------------------------------
    /// lastmodified:[2000-1-1 TO 2000-2-1] | Have lastmodified values between '2000-1-1' and '2000-2-1'
    /// square brackets denote an inclusive range, and curly brackets denote an exclusive range
    /// ---------------------------------------------------------------------------------
    /// </summary>
    public class CustomQueryParser : QueryParser
    {
            /**
	     * Static parse method which will query both the title and the
				    fullcontents fields via a BooleanQuery
	     */
        static private readonly log4net.ILog logger = log4net.LogManager.GetLogger(typeof(CustomQueryParser));

        /// <summary>
        /// the method parses rich expressions into one of the Query implementations
        /// 
        /// </summary>
        /// <param name="query">the query is the expression to be parsed, such as "+cat+dog".</param>
        /// <param name="fields">fields is the array to collect default fields</param>
        /// <param name="analyzer"></param>
        /// <returns></returns>
	    public static Query Parse(String query, String[] fields, Analyzer analyzer) {
    				
           BooleanQuery bQuery = new BooleanQuery();

           for (int i = 0; i < fields.Length; i++) {
               QueryParser parser = new CustomQueryParser(fields[i], analyzer);
               Query q = parser.Parse(query);
               //Use this operator for clauses that should appear in the matching documents
               //BooleanClause.Occur.MUST_NOT means this operator for clauses that must not appear in the matching documents
               //BooleanClause.Occur.MUST means this operator for clauses that must appear in the matching documents
               bQuery.Add(q,BooleanClause.Occur.SHOULD); // combine the queries, neither requiring or prohibiting matches
           }
           logger.Info(string.Format("search string:{0}", bQuery.ToString()));
           return bQuery;
        }

        public CustomQueryParser(String field, Analyzer analyzer)
            : base(field, analyzer)
        {
		   
	    }

	    protected Query getWildcardQuery(String field, String term){
		    throw new ParseException("Wildcard Query not allowed.");
	    }

	    protected Query getFuzzyQuery(String field, String term) {
		    throw new ParseException("Fuzzy Query not allowed.");
	    }

    }
}
